use crate::tessellator::{ActiveEdge, Tessellator};
use crate::{tessellator, Callbacks, LineIterator};

mod clipper;
mod poligon;

use clipper::*;

pub use poligon::Polygon;

#[derive(Clone, Debug)]
pub struct Filler {
	clipper: Clipper,
	clipper_pending_edges: Vec<PendingEdge>,
	clipper_left_edges: Vec<usize>,
	clipper_right_edges: Vec<usize>,
	clipper_left_boundary_edge_indices: Vec<usize>,
	clipper_right_boundary_edge_indices: Vec<usize>,
	tessellator: Tessellator,
	tessellator_pending_edges: Vec<tessellator::PendingEdge>,
	tessellator_left_edges: Vec<ActiveEdge>,
}
impl Default for Filler {
	fn default() -> Self {
		Self::new()
	}
}
impl Filler {
	pub fn new() -> Self {
		Self {
			clipper: Clipper::new(),
			clipper_pending_edges: Vec::new(),
			clipper_left_edges: Vec::new(),
			clipper_right_edges: Vec::new(),
			clipper_left_boundary_edge_indices: Vec::new(),
			clipper_right_boundary_edge_indices: Vec::new(),
			tessellator: Tessellator::new(),
			tessellator_pending_edges: Vec::new(),
			tessellator_left_edges: Vec::new(),
		}
	}
	pub fn reset(&mut self) -> &mut Self {
		self.clipper.reset();
		self.clipper_pending_edges.clear();
		self.clipper_left_edges.clear();
		self.clipper_right_edges.clear();
		self.clipper_left_boundary_edge_indices.clear();
		self.clipper_right_boundary_edge_indices.clear();
		self.tessellator.reset();
		self.tessellator_pending_edges.clear();
		self.tessellator_left_edges.clear();
		self
	}
	pub fn fill(&mut self, polygons: &[Polygon], fill_rule: FillRule, callbacks: &mut impl Callbacks) {
		self.tessellator.tessellate(
			self.clipper.clip_polygons(
				Operation::Union,
				polygons,
				&[],
				ClipperOptions {
					subject_fill_rule: fill_rule,
					..ClipperOptions::default()
				},
				&mut self.clipper_pending_edges,
				&mut self.clipper_left_edges,
				&mut self.clipper_right_edges,
				&mut self.clipper_left_boundary_edge_indices,
				&mut self.clipper_right_boundary_edge_indices,
			),
			callbacks,
			&mut self.tessellator_pending_edges,
			&mut self.tessellator_left_edges,
		);
	}
	pub fn fill_iter(&mut self, polygons: impl LineIterator, fill_rule: FillRule, callbacks: &mut impl Callbacks) {
		self.tessellator.tessellate(
			self.clipper.clip(
				Operation::Union,
				polygons,
				core::iter::empty(),
				ClipperOptions {
					subject_fill_rule: fill_rule,
					..ClipperOptions::default()
				},
				&mut self.clipper_pending_edges,
				&mut self.clipper_left_edges,
				&mut self.clipper_right_edges,
				&mut self.clipper_left_boundary_edge_indices,
				&mut self.clipper_right_boundary_edge_indices,
			),
			callbacks,
			&mut self.tessellator_pending_edges,
			&mut self.tessellator_left_edges,
		);
	}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FillRule {
	NonZero,
	EvenOdd,
}

impl FillRule {
	fn apply(self, winding: i32) -> bool {
		match self {
			FillRule::NonZero => winding != 0,
			FillRule::EvenOdd => winding % 2 != 0,
		}
	}
}

impl Default for FillRule {
	fn default() -> Self {
		FillRule::NonZero
	}
}
